<template>
  <div class="viewer-container">
    <div class="controller-bar">
      <Space>
        <ButtonGroup>
          <Button type="primary">
            打开文件
          </Button>
          <Button type="primary">下载</Button>
          <Button type="primary" @click="doSave">保存</Button>
          <Button type="primary">
            预览
          </Button>
          <Button type="primary">
            模拟
          </Button>
        </ButtonGroup>

        <ButtonGroup>
          <Button >
            test
          </Button>
          <Button >下载</Button>
          <Button >保存</Button>
          <Button >
            预览
          </Button>
          <Button >
            模拟
          </Button>
        </ButtonGroup>
      </Space>
    </div>
    <div class="canvas" id="js-canvas"></div>
    <div class="properties-panel" >
      <div class="properties-panel-switch">
        <div class="properties-panel-switch-icon">
          <CaretRightOutlined />
          <CaretLeftOutlined />
        </div>
        属性
      </div>
      <div id="js-properties-panel"></div>
    </div>
  </div>
</template>

<script>
import {
  BpmnPropertiesPanelModule,
  BpmnPropertiesProviderModule
} from 'bpmn-js-properties-panel';

import "bpmn-js/dist/assets/diagram-js.css";
import "bpmn-js/dist/assets/bpmn-js.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
import "bpmn-js-properties-panel/dist/assets/properties-panel.css";

import BpmnModeler from 'bpmn-js/lib/Modeler';
import BpmnViewer from 'bpmn-js/lib/Viewer'
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
import {Spin, Tag, Popover, Icon, Button, Space, Affix, ButtonGroup} from "ant-design-vue";
import customTranslate from './customTranslate/customTranslate';

import {
  PlusCircleOutlined, MinusCircleOutlined,
  OneToOneOutlined, PlusOutlined,
  MinusOutlined, RetweetOutlined,
  ExpandOutlined, CompressOutlined,
  CaretRightOutlined,
  CaretLeftOutlined,
} from '@ant-design/icons-vue';

let bpmnViewer = null;
let bpmnModeler = null;
const customTranslateModule = {
  translate: [ 'value', customTranslate ]
};
export default {
  name: 'BpmnDiagram',
  components: {
    PlusCircleOutlined, MinusCircleOutlined,
    OneToOneOutlined, PlusOutlined,
    MinusOutlined, RetweetOutlined,
    ExpandOutlined, CompressOutlined,
    CaretRightOutlined, CaretLeftOutlined,
    Spin, Tag, Popover, Button, Space, Affix, ButtonGroup, Icon
  },
  props: {
    xmlStr: String,
    modelInfo: Object,
  },
  data() {
    return {
      bpmnCanvasId: 'bpmnCanvas' + new Date().getTime(),
      defaultZoom: 1,
      fitViewScaleRate: 1,
      isFitView: false,
    }
  },
  mounted() {
    this.initData();
    this.openDiagram(this.modelInfo);
    // this.importXml(this.modelInfo);
  },
  methods: {
    async getXml(){
      const { xml } = await bpmnModeler.saveXML({ format: true });
      return xml;
    },
    async doSave(){
      const { xml } = await bpmnModeler.saveXML({ format: true });
      return xml;
    },
    initData() {

      bpmnModeler && bpmnModeler.destroy();
      bpmnModeler = new BpmnModeler({
        container: '#js-canvas',
        propertiesPanel: {
          parent: '#js-properties-panel'
        },
        additionalModules: [
          customTranslateModule,
          BpmnPropertiesPanelModule,
          BpmnPropertiesProviderModule,
          // magicPropertiesProviderModule
        ],
        moddleExtensions: {
          // magic: magicModdleDescriptor
        }
      });


      bpmnViewer && bpmnViewer.destroy();
      bpmnViewer = new BpmnViewer({
        container: document.getElementById(this.bpmnCanvasId),
        width: '100%',
        additionalModules: [
          MoveCanvasModule // 移动整个画布
        ],
        /*keyboard: {
          bindTo: document
        }*/
      });
      // const tempXml = ``;


    },

    async openDiagram(modelInfo) {
      const xml = modelInfo.modelXml;

      try {

        await bpmnModeler.importXML(xml);

        const canvas = bpmnModeler.get('canvas');
        canvas.zoom("fit-viewport", "auto");
        // container
        //   .removeClass('with-error')
        //   .addClass('with-diagram');
      } catch (err) {
        // container
        //   .removeClass('with-diagram')
        //   .addClass('with-error');

        // container.find('.error pre').text(err.message);

        console.error(err);
      }
    },


    importXml(modelInfo) {
      const that = this;
      // 处理排他网关， 注：流程图预览时，排他网关需要在对应的<bpmndi:BPMNShape>节点上添加属性isMarkerVisible="true"
      const gatewayIds = this.getHtmlAttr(modelInfo.modelXml, 'exclusiveGateway', 'id');
      let modelXmlTemp = modelInfo.modelXml;
      if(gatewayIds && gatewayIds.length > 0){
        gatewayIds.forEach(item=>{
          const result = new RegExp('id="(.+?)"').exec(item)
          if(result && result[1]){
            modelXmlTemp = modelXmlTemp.replace('bpmnElement="'+result[1]+'"', 'bpmnElement="'+result[1]+'" isMarkerVisible="true"');
          }
        })
      }

      bpmnViewer.importXML(modelXmlTemp, function (err) {
        if(err){
          console.error(err);
        }else{
          that.importXmlSuccess();
          that.genBpmnSvgMarker();
        }
      });
    },
    importXmlSuccess() {
      // 使流程图自适应屏幕
      const canvas = bpmnViewer.get('canvas');
      canvas.zoom("fit-viewport", "auto");
      // this.defaultZoom = canvas.zoom();
      // this.fitViewScaleRate = canvas.zoom();
      this.setViewerStyle(canvas);
      // this.bindEvents();
    },
    processZoomIn(zoomStep = 0.1) {
      let newZoom = Math.floor(this.defaultZoom * 100 + zoomStep * 100) / 100;
      if (newZoom > 4) {
        newZoom = 4;
        // throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");
      }
      this.defaultZoom = newZoom;
      bpmnViewer.get("canvas").zoom(this.defaultZoom);
    },

    processZoomOut(zoomStep = 0.1) {
      let newZoom = Math.floor(this.defaultZoom * 100 - zoomStep * 100) / 100;
      if (newZoom < 0.2) {
        newZoom = 0.2
        // throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");
      }
      this.defaultZoom = newZoom;
      bpmnViewer.get("canvas").zoom(this.defaultZoom);
    },

    processReZoom() {
      if (bpmnViewer.get("canvas")) {
        this.defaultZoom = 1;
        bpmnViewer.get("canvas").zoom("fit-viewport", "auto");
      }
    },

    processFitDialog(isFit) {
      if (bpmnViewer.get("canvas")) {
        const canvas = bpmnViewer.get('canvas');
        if (isFit) {
          this.isFitView = false;
          bpmnViewer.get("canvas").zoom("fit-viewport", "auto");

          this.defaultZoom = canvas.zoom()
        } else {
          this.isFitView = true;
          this.defaultZoom = 1;
          bpmnViewer.get("canvas").zoom(this.defaultZoom);
        }
      }
    },

    getHtmlAttr(source, element, attr) {
      let result = [];
      let reg = "<" + element + "[^<>]*?\\s" + attr + "=['\"]?(.*?)['\"]?\\s.*?>";
      let matched = source.match(new RegExp(reg, "gi"));

      matched&&matched.forEach(item=>{
        item&&result.push(item);
      });
      return result;
    },

    // 向画布中添加一个节点-箭头颜色的实现
    genBpmnSvgMarker(){
      // 向画布中添加一个节点-箭头颜色的实现
      let bpmnCanvas = document.getElementById(this.bpmnCanvasId);
      let bpmnSvg = bpmnCanvas.querySelector('.djs-container').querySelector('svg')
      let bpmnSvgDefs = bpmnSvg.querySelector('defs');
      let marker = document.createElementNS("http://www.w3.org/2000/svg","marker");
      if(marker){
        marker.setAttribute("id", "greenMarker")
        marker.setAttribute("viewBox", "0 0 20 20")
        marker.setAttribute("refX", "11")
        marker.setAttribute("refY", "10")
        marker.setAttribute("markerWidth", "10")
        marker.setAttribute("markerHeight", "10")
        marker.setAttribute("orient", "auto")
        let path = document.createElementNS("http://www.w3.org/2000/svg","path");
        path.setAttribute("d", "M 1 5 L 11 10 L 1 15 Z");
        path.setAttribute("style", "fill: #00be00; stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1; stroke: #00be00;");
        marker.appendChild(path);
        bpmnSvgDefs.appendChild(marker);
      }
    },
    setViewerStyle(canvas){
      const {hisActiveActivityIds, highLightedFlows, activeActivityIds} = this.modelInfo;
      // 历史节点中，将当前高亮节点排除，只剩下历史非高亮节点
      if(hisActiveActivityIds && hisActiveActivityIds.length>0){
        const tempHisActiveActivityIds = hisActiveActivityIds.filter((item1) => !activeActivityIds.some((item2) => item1 === item2));
        if(tempHisActiveActivityIds && tempHisActiveActivityIds.length > 0){
          tempHisActiveActivityIds.forEach(item=>{
            canvas.addMarker(item, 'hishighlight');
          });
        }
      }

      if(activeActivityIds && activeActivityIds.length > 0){
        activeActivityIds.forEach(item=>{
          canvas.addMarker(item, 'highlight');
        });
      }
      // 获取所有当前高亮节点，增加蚂蚁线
      const hightlightEle = document.querySelectorAll('.highlight');
      hightlightEle.forEach(item=>{
        const ele = item.querySelector('.djs-visual rect');
        if(ele){
          ele.setAttribute('stroke-dasharray', '4,4');
        }
      })

      if(highLightedFlows && highLightedFlows.length > 0){
        highLightedFlows.forEach(item=>{
          canvas.addMarker(item, 'highlight-line');
        });
      }
    },

    // 预览流程图时 - 鼠标滚动缩放
    changeScale(e) {
      const scal = e.deltaY > 0 ? -0.1 : 0.1;
      if (this.defaultZoom < 0.2) {
        this.defaultZoom = 0.2
      }
      if (this.defaultZoom > 4.0) {
        this.defaultZoom = 4.0;
      }
      this.defaultZoom = this.defaultZoom + scal;
      bpmnViewer.get("canvas").zoom(this.defaultZoom);

      if (this.defaultZoom < this.fitViewScaleRate) {
        this.isFitView = false;
      } else {
        this.isFitView = true;
      }
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="less">
.viewer-container {
  position: absolute;
  width: 100%;
  height: 100%;

  .canvas {
    width: 100%;
    height: 100%;
  }

  .svg-controller {
    text-align: center;
    position: absolute;
    bottom: -5px;
    opacity: 0;
    transition: 0.8s;
    margin: auto;
    width: 100%;

    .scale-rate {
      font-size: 14px;
      line-height: 20px;
    }
  }

  &:hover {
    .svg-controller {
      bottom: 5px;
      opacity: 1;
      z-index: 9;
    }
  }

  .svg-container {
    height: 100%;
    cursor: move;
  }

  .djs-overlay-container {
    font-size: initial;

    .popover-title {
      font-size: 20px;
      line-height: 30px;
      margin-bottom: 0;
    }
  }

  .bpmnCanvas{
    .bjs-container{
      overflow: visible;
      padding: 0;
      .djs-container{
        overflow: visible!important;
        .djs-overlay-container{
          z-index: 9;
        }
      }
    }
  }
}

.hishighlight:not(.djs-connection) .djs-visual > :nth-child(1) {
  fill: rgba(211, 238, 211, 0.99) !important; /* color elements as green */
}
.hishighlight g.djs-visual >:nth-child(1) {
  stroke: rgba(0, 190, 0, 1) !important;
}
.highlight-line g.djs-visual >:nth-child(1) {
  stroke: rgba(0, 190, 0, 1) !important;
}
.highlight-line{
  path{
    marker-end: url('#greenMarker') !important;
  }
}

.highlight:not(.djs-connection) .djs-visual > :nth-child(1) {
  fill: rgba(251, 233, 209, 1) !important; /* color elements as green */
}
.highlight g.djs-visual >:nth-child(1) {
  stroke: rgba(214, 126, 125, 1) !important;
}

@keyframes dynamicNode {
  to {
    stroke-dashoffset: 100%;
  }
}
@-webkit-keyframes dynamicNode {
  to {
    stroke-dashoffset: 100%;
  }
}
.highlight{
  .djs-visual{
    animation: dynamicNode 18S linear infinite;
    -webkit-animation: dynamicNode 18S linear infinite;
    -webkit-animation-fill-mode: forwards;
  }
}
.containers {
  width: 100%;
  height: 100%;

  .canvas {
    width: 100%;
    height: 100%;
  }
}

.djs-palette{
  top: 50px;
}

.controller-bar{
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 40px;
  background: #eee;
  z-index: 999;
  line-height: 40px;
}

.properties-panel{
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 360px;

  background: white;
  z-index: 99999;
  outline: 1px solid #ccc;
  .properties-panel-switch{
    font-size: 20px;
    font-weight: bold;
    text-align: center;
    line-height: 30px;
    position: absolute;
    left: -40px;
    top: 0;
    width: 40px;
    height: 100%;
    z-index: 999991;
    background: #e5e7ec;
    cursor: pointer;
    border: 1px solid red;
    &:hover{
      background: #E5E7ECFF;
    }
  }
  &::after{
  }
  .bio-properties-panel-container{

  }
}
</style>
